"""
云存储统一客户端
作为统一入口点，提供简洁的API接口
"""

import logging
import os
from typing import Any, BinaryIO, Callable, Dict, List, Optional, Union

from .base_client import (
    AccountInfo,
    FileInfo,
    LoginCredentials,
    PersistentLoginInfo,
    TrashItem,
)
from .clouds_file_system import CloudFileSystem
# from .persistence import PersistenceManager


class CloudsClient:
    """云存储统一客户端，提供统一的云盘操作接口"""
    
    def __init__(self, provider: str = "", username: str = "", 
                #  persistence_manager: Optional[PersistenceManager] = None,
                 on_persistent_info_updated: Optional[Callable[[str, str, PersistentLoginInfo], None]] = None,
                 enable_cache: bool = True, cache_config: Optional[Dict[str, Any]] = None):
        """
        初始化云存储客户端
        
        Args:
            provider: 云盘提供商
            username: 用户名
            persistence_manager: 持久化管理器
            on_persistent_info_updated: 持久化信息更新回调函数
            enable_cache: 是否启用缓存功能
            cache_config: 缓存配置参数
        """
        self.provider = provider
        self.username = username
        self.file_system = CloudFileSystem(
            # persistence_manager=persistence_manager,
            on_persistent_info_updated=on_persistent_info_updated,
            enable_cache=enable_cache,
            cache_config=cache_config
        )
        self.logger = logging.getLogger(__name__)
    
    def _normalize_path(self, path: str) -> str:
        """
        标准化路径格式
        
        Args:
            path: 原始路径
            
        Returns:
            str: 标准化后的路径
        """
        if not path:
            return "/"
        
        # 统一使用正斜杠
        path = path.replace('\\', '/')
        
        # 确保以/开头
        if not path.startswith('/'):
            path = '/' + path
        
        # 移除重复的斜杠
        while '//' in path:
            path = path.replace('//', '/')
        
        # 根目录特殊处理
        if path == '/':
            return path
        
        # 移除末尾的斜杠
        if path.endswith('/'):
            path = path[:-1]
        
        return path
    
    def _validate_provider_and_username(self) -> bool:
        """
        验证实例的提供商和用户名参数
        
        Returns:
            bool: 验证是否通过
        """
        if not self.provider or not isinstance(self.provider, str):
            self.logger.error("提供商参数无效")
            return False
        
        if not self.username or not isinstance(self.username, str):
            self.logger.error("用户名参数无效")
            return False
        
        return True
    
    # ==============================
    # 云盘提供商管理
    # ==============================
    
    def get_available_providers(self) -> List[str]:
        """获取可用的云盘提供商列表"""
        return self.file_system.get_available_providers()
    
    def set_account(self, provider: str, username: str):
        """
        设置云盘账号信息
        
        Args:
            provider: 云盘提供商
            username: 用户名
        """
        self.provider = provider
        self.username = username
    
    # ==============================
    # 账号管理接口
    # ==============================
    
    # def add_account(self, provider: str, username: str, password: str = None, 
    #                extra_credentials: Dict[str, Any] = None, save_persistent: bool = True) -> PersistentLoginInfo:
    #     """
    #     添加云盘账号（首次登录）
        
    #     Args:
    #         provider: 云盘提供商
    #         username: 用户名
    #         password: 密码
    #         extra_credentials: 额外的登录凭据
    #         save_persistent: 是否保存持久化信息
    #     """
    #     credentials = LoginCredentials(
    #         provider=provider,
    #         username=username,
    #         password=password,
    #         extra_params=extra_credentials or {}
    #     )
    #     return self.file_system.add_account(provider, credentials, save_persistent)
    
    # def load_account(self, provider: str, username: str, password: str = None,
    #                 extra_credentials: Dict[str, Any] = None,
    #                 persistent_info: Optional[PersistentLoginInfo] = None,
    #                 auto_load_persistent: bool = True,
    #                 save_persistent: bool = True) -> bool:
    #     """
    #     加载云盘账号（支持持久化登录）
        
    #     Args:
    #         provider: 云盘提供商
    #         username: 用户名
    #         password: 密码
    #         extra_credentials: 额外的登录凭据
    #         persistent_info: 持久化信息（可选）
    #         auto_load_persistent: 是否自动从持久化管理器加载信息
    #         save_persistent: 重新登录时是否保存新的持久化信息
    #     """
    #     credentials = LoginCredentials(
    #         provider=provider,
    #         username=username,
    #         password=password,
    #         extra_params=extra_credentials or {}
    #     )
    #     return self.file_system.load_account(
    #         provider, username, credentials, persistent_info, 
    #         auto_load_persistent, save_persistent
    #     )
    
    # def remove_account(self, provider: str, username: str, remove_persistent: bool = True) -> bool:
    #     """
    #     移除云盘账号
        
    #     Args:
    #         provider: 云盘提供商
    #         username: 用户名
    #         remove_persistent: 是否同时删除持久化信息
    #     """
    #     return self.file_system.remove_account(provider, username, remove_persistent)
    
    # def list_accounts(self) -> List[Dict[str, str]]:
    #     """列出已加载的账号"""
    #     return self.file_system.list_accounts()
    
    # def list_persistent_accounts(self) -> List[Dict[str, str]]:
    #     """列出所有持久化保存的账号"""
    #     return self.file_system.list_persistent_accounts()
    
    # def cleanup_expired_accounts(self) -> int:
    #     """清理过期的持久化账号信息"""
    #     return self.file_system.cleanup_expired_accounts()
    
    # def refresh_account(self, provider: str, username: str) -> Optional[PersistentLoginInfo]:
    #     """刷新账号登录状态"""
    #     return self.file_system.refresh_account(provider, username)
    
    # ==============================
    # 文件操作接口
    # ==============================
    
    def quick_upload(self, file_md5: str, remote_path: str, **kwargs) -> bool:
        """
        快速上传（秒传）
        - file_md5: 文件MD5值
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        return self.file_system.quick_upload(self.provider, self.username, file_md5, remote_path, **kwargs)
    
    # def upload_file(self, file_stream: Union[str, bytes, BinaryIO], 
    #                remote_path: str, **kwargs) -> bool:
    #     """
    #     上传文件（支持秒传）
    #     - file_stream: 文件流、文件路径或字节数据
    #     - remote_path: 远程路径
    #     - **kwargs: 额外参数（如overwrite等）
    #     """
    #     if not self._validate_provider_and_username():
    #         return False
        
    #     remote_path = self._normalize_path(remote_path)
        
    #     try:
    #         return self.file_system.upload_file(self.provider, self.username, file_stream, remote_path, **kwargs)
    #     except Exception as e:
    #         self.logger.error(f"上传文件失败: {e}")
    #         return False
    

    def check_quick_upload(self, file_md5: str) -> bool:
        """
        检查是否可以秒传
        
        Args:
            file_md5: 文件MD5值
            
        Returns:
            bool: 是否可以秒传
        """
        if not self._validate_provider_and_username():
            return False
        
        try:
            return self.file_system.check_quick_upload(self.provider, self.username, file_md5)
        except Exception as e:
            self.logger.error(f"秒传检查失败: {e}")
            return False

    def get_download_url(self, remote_path: str, expires_in: int = 3600) -> str:
        """
        获取下载链接
        - remote_path: 远程路径
        - expires_in: 链接有效期（秒）
        """
        if not self._validate_provider_and_username():
            return ""
        
        remote_path = self._normalize_path(remote_path)
        return self.file_system.get_download_url(self.provider, self.username, remote_path, expires_in)
    
    def mkdir(self, remote_path: str) -> bool:
        """
        创建目录
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        try:
            return self.file_system.create_folder(self.provider, self.username, remote_path)
        except Exception as e:
            self.logger.error(f"创建目录失败: {e}")
            return False
    
    def ls(self, remote_path: str = "/") -> List[Dict[str, Any]]:
        """
        列出目录内容
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return []
        
        remote_path = self._normalize_path(remote_path)
        try:
            files = self.file_system.list_files(self.provider, self.username, remote_path)
            return [self._serialize_file_info(f) for f in files]
        except Exception as e:
            self.logger.error(f"列出目录内容失败: {e}")
            return []
    
    def stat(self, remote_path: str) -> Dict[str, Any]:
        """
        获取文件/目录信息
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return {}
        
        remote_path = self._normalize_path(remote_path)
        try:
            file_info = self.file_system.get_file_info(self.provider, self.username, remote_path)
            return self._serialize_file_info(file_info)
        except Exception as e:
            self.logger.error(f"获取文件信息失败: {e}")
            return {}
    
    def exists(self, remote_path: str) -> bool:
        """
        检查文件/目录是否存在
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        try:
            return self.file_system.file_exists(self.provider, self.username, remote_path)
        except Exception as e:
            self.logger.error(f"检查文件存在性失败: {e}")
            return False
    
    def is_dir(self, remote_path: str) -> bool:
        """
        检查是否为目录
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        try:
            file_info = self.file_system.get_file_info(self.provider, self.username, remote_path)
            # 处理字典类型的file_info
            if isinstance(file_info, dict):
                return file_info.get('isFolder', False)
            # 处理FileInfo对象类型
            elif hasattr(file_info, 'is_dir'):
                return file_info.is_dir
            else:
                return False
        except:
            return False
    
    def mv(self, src_path: str, dst_path: str) -> bool:
        """
        移动文件/目录
        - src_path: 源路径
        - dst_path: 目标路径
        """
        if not self._validate_provider_and_username():
            return False
        
        src_path = self._normalize_path(src_path)
        dst_path = self._normalize_path(dst_path)
        return self.file_system.move_file(self.provider, self.username, src_path, dst_path)
    
    def copy_file(self, src_path: str, dst_path: str) -> bool:
        """
        复制文件/目录
        - src_path: 源路径
        - dst_path: 目标路径
        """
        if not self._validate_provider_and_username():
            return False
        
        src_path = self._normalize_path(src_path)
        dst_path = self._normalize_path(dst_path)
        try:
            return self.file_system.copy_file(self.provider, self.username, src_path, dst_path)
        except Exception as e:
            self.logger.error(f"复制文件失败: {e}")
            return False
    
    def move_file(self, src_path: str, dst_path: str) -> bool:
        """
        移动文件/目录
        - src_path: 源路径
        - dst_path: 目标路径
        """
        if not self._validate_provider_and_username():
            return False
        
        src_path = self._normalize_path(src_path)
        dst_path = self._normalize_path(dst_path)
        try:
            return self.file_system.move_file(self.provider, self.username, src_path, dst_path)
        except Exception as e:
            self.logger.error(f"移动文件失败: {e}")
            return False
    
    def rename_file(self, remote_path: str, new_name: str) -> bool:
        """
        重命名文件/目录
        - remote_path: 远程路径
        - new_name: 新名称
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        try:
            return self.file_system.rename_file(self.provider, self.username, remote_path, new_name)
        except Exception as e:
            self.logger.error(f"重命名文件失败: {e}")
            return False
    
    # ==============================
    # 文件操作接口（兼容性别名）
    # ==============================
    
    def cp(self, src_path: str, dst_path: str) -> bool:
        """
        复制文件/目录（别名）
        - src_path: 源路径
        - dst_path: 目标路径
        """
        return self.copy_file(src_path, dst_path)
    
    def rename(self, remote_path: str, new_name: str) -> bool:
        """
        重命名文件/目录（别名）
        - remote_path: 远程路径
        - new_name: 新名称
        """
        return self.rename_file(remote_path, new_name)
    
    def rm(self, remote_path: str) -> bool:
        """
        删除文件/目录（移到回收站）
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        return self.file_system.delete_file(self.provider, self.username, remote_path, permanent=False)
    
    def delete_file(self, remote_path: str, permanent: bool = False) -> bool:
        """
        删除文件
        - remote_path: 远程路径
        - permanent: 是否永久删除
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        return self.file_system.delete_file(self.provider, self.username, remote_path, permanent)

    def rm_force(self, remote_path: str) -> bool:
        """
        强制删除文件/文件夹（永久删除）
        - remote_path: 远程路径
        """
        if not self._validate_provider_and_username():
            return False
        
        remote_path = self._normalize_path(remote_path)
        return self.file_system.delete_file(self.provider, self.username, remote_path, permanent=True)
    
    # ==============================
    # 账号信息接口
    # ==============================
    
    def get_account_info(self) -> Optional[Dict[str, Any]]:
        """
        获取账号信息
        """
        if not self._validate_provider_and_username():
            return None
        
        account_info = self.file_system.get_account_info(self.provider, self.username)
        if account_info:
            return {
                'username': account_info.username,
                'total_space': account_info.total_space,
                'used_space': account_info.used_space,
                'available_space': account_info.available_space,
                'extra_info': account_info.extra_info
            }
        return None
    
    # ==============================
    # 回收站接口
    # ==============================
    
    def list_trash(self) -> List[Dict[str, Any]]:
        """
        列出回收站内容
        """
        if not self._validate_provider_and_username():
            return []
        
        trash_items = self.file_system.list_trash(self.provider, self.username)
        return [self._serialize_trash_item(item) for item in trash_items]
    
    def restore_from_trash(self, original_path: str, target_path: Optional[str] = None) -> bool:
        """
        从回收站恢复文件
        - original_path: 原始路径
        - target_path: 目标路径（可选）
        """
        if not self._validate_provider_and_username():
            return False
        
        return self.file_system.restore_from_trash(self.provider, self.username, original_path, target_path)
    
    def delete_from_trash(self, original_path: str) -> bool:
        """
        从回收站永久删除
        - original_path: 原始路径
        """
        if not self._validate_provider_and_username():
            return False
        
        return self.file_system.delete_from_trash(self.provider, self.username, original_path)
    
    def empty_trash(self) -> int:
        """
        清空回收站
        返回删除的项目数量
        """
        if not self._validate_provider_and_username():
            return 0
        
        return self.file_system.empty_trash(self.provider, self.username)
    
    def get_trash_item_info(self, original_path: str) -> Optional[Dict[str, Any]]:
        """
        获取回收站项目信息
        - original_path: 原始路径
        """
        if not self._validate_provider_and_username():
            return None
        
        trash_item = self.file_system.get_trash_item_info(self.provider, self.username, original_path)
        return self._serialize_trash_item(trash_item) if trash_item else None
    
    # ==============================
    # 辅助方法
    # ==============================
    
    def _serialize_file_info(self, file_info) -> Dict[str, Any]:
        """序列化文件信息"""
        # 处理字典类型的file_info（来自get_file_info的返回值）
        if isinstance(file_info, dict):
            return {
                'name': file_info.get('name', ''),
                'path': file_info.get('path', ''),
                'is_dir': file_info.get('isFolder', False),
                'size': file_info.get('size', 0),
                'md5': file_info.get('md5', ''),
                'created_at': file_info.get('createTime', ''),
                'updated_at': file_info.get('updateTime', '')
            }
        # 处理FileInfo对象类型
        elif hasattr(file_info, 'name'):
            return {
                'name': file_info.name,
                'path': file_info.path,
                'is_dir': file_info.is_dir,
                'size': file_info.size,
                'md5': file_info.md5,
                'created_at': file_info.created_at.isoformat() if file_info.created_at else None,
                'updated_at': file_info.updated_at.isoformat() if file_info.updated_at else None
            }
        else:
            # 如果file_info为None或其他类型，返回空字典
            return {
                'name': '',
                'path': '',
                'is_dir': False,
                'size': 0,
                'md5': '',
                'created_at': None,
                'updated_at': None
            }
    
    def _serialize_trash_item(self, trash_item: TrashItem) -> Dict[str, Any]:
        """序列化回收站项目信息"""
        return {
            'name': trash_item.name,
            'original_path': trash_item.original_path,
            'deleted_at': trash_item.deleted_at.isoformat() if trash_item.deleted_at else None,
            'size': trash_item.size,
            'is_dir': trash_item.is_dir
        }